#include "HighYieldBond.h"

#include <iostream>
#include <sstream>

#include "BondContainer.h"
#include "QBIssuerInfo.h"
#include "QBProviceInfo.h"

CHighYieldBond& CHighYieldBond::instance() {
  static CHighYieldBond s_hyb;
  return s_hyb;
}

CHighYieldBond::CHighYieldBond() { ClearData(); }

CHighYieldBond::~CHighYieldBond() {}

void CHighYieldBond::UpdateData(xQBHighYieldBondListAck_c* pAck) {
  std::lock_guard<std::mutex> locker(m_mutex);
  if (!pAck) {
    return;
  }
  std::string combBondKey;
  for (auto& it : pAck->m_List) {
    combBondKey =
        std::string(it.m_bondkey) + "." + std::string(it.m_listedmarket);
    m_mapHighYieldBond[combBondKey] = it;
  }

  /*�����ô���
          SYSTEMTIME st;
          GetLocalTime(&st);
          std::ostringstream ostr;
          ostr << "E:\\dat\\" << st.wYear << st.wMonth << st.wDay << st.wHour <<
     st.wMinute << st.wSecond << ".txt" <<std::endl; string strFile =
     ostr.str(); strFile.erase(strFile.end() - 1);

          FILE* pFile = fopen(strFile.c_str(), "a+");
          if (pFile != NULL)
          {
                  string str;
                  for (auto& it = pAck->m_List.begin(); it !=
     pAck->m_List.end(); ++it) { CBondInfo bi;
                          AfxGetBondContainer().GetBondInfoByKey(it->m_bondkey,
     it->m_listedmarket, &bi); str = string(it->m_bondkey) + "." +
     string(it->m_listedmarket) + "===>" + string(bi.GetCombBondCode());
                          fputs(str.c_str(), pFile);
                          fputs("\r", pFile);
                  }
                  fclose(pFile);
          }*/
}

void CHighYieldBond::ClearData() {
  std::lock_guard<std::mutex> locker(m_mutex);
  m_mapHighYieldBond.clear();
}

bool CHighYieldBond::CheckHighYieldBond(int bondIndex,
                                        const BLHCONDITION& cond) {
  if (!CBondContainer::instance().IsValidIndex(bondIndex)) return false;

  if (cond.nHighYieldBond[0] == CBondContainer::HYBAll) return true;
  if (cond.nHighYieldBond[0] == CBondContainer::HYBNone) return false;

  std::string combBondKey = GetCombBondKey(bondIndex);
  if (combBondKey == "") {
    return false;
  }

  auto it = m_mapHighYieldBond.find(combBondKey);
  bool bIsHighYieldBond = (it != m_mapHighYieldBond.end());
  const CBondInfo& bi = CBondContainer::instance().ElementAtR(bondIndex);
  CQBIssuerInfo& IMap = CQBIssuerInfo::instance();
  const IssuerInfo* pI = IMap.GetIssuerInfo((const char*)bi.GetIssuerCode());
  const QBPROVINCEINFO* pArea =
      pI ? CQBProvinceInfo::instance().GetProviceInfo(
               pI->field((int)kIssuerInfo::Province_Code))
         : nullptr;
  static const char strSW_Realty[] = "0315";
  for (int i = 0; i < sizeof(cond.nHighYieldBond) / sizeof(int); i++) {
    if (cond.nHighYieldBond[i] == CBondContainer::HYBNohigh &&
        !bIsHighYieldBond) {
      return true;
    } else if (bIsHighYieldBond) {
      switch (cond.nHighYieldBond[i]) {
        case CBondContainer::HYBMunicipal: {
          if (bi.IsMunicipal()) {
            return true;
          }
        } break;
        case CBondContainer::HYBMunicipal_NorthWest: {
          static std::vector<std::string> vctNW = {"SNPRN", "GSPRN", "QHPRN",
                                                   "NXPRN", "XJPRN", "IMPRN"};
          if (!pArea || !bi.IsMunicipal()) break;
          if (std::find(vctNW.begin(), vctNW.end(), pArea->Area_Code) !=
              vctNW.end())
            return true;
        } break;
        case CBondContainer::HYBMunicipal_SouthWest: {
          static std::vector<std::string> vctSW = {"CQPRN", "GXPRN", "SCPRN",
                                                   "GZPRN", "YNPRN", "XZPRN"};
          if (!bi.IsMunicipal()) break;
          if (std::find(vctSW.begin(), vctSW.end(), pArea->Area_Code) !=
              vctSW.end())
            return true;
        } break;
        case CBondContainer::HYBMunicipal_NorthEast: {
          static std::vector<std::string> vctNE = {"LNPRN", "JLPRN", "HLPRN"};
          if (!bi.IsMunicipal()) break;
          if (std::find(vctNE.begin(), vctNE.end(), pArea->Area_Code) !=
              vctNE.end())
            return true;
        } break;
        case CBondContainer::HYBMunicipal_Center: {
          static std::vector<std::string> vctC = {"SXPRN", "AHPRN", "JXPRN",
                                                  "HAPRN", "HBPRN", "HNPRN"};
          if (!bi.IsMunicipal()) break;
          if (std::find(vctC.begin(), vctC.end(), pArea->Area_Code) !=
              vctC.end())
            return true;
        } break;
        case CBondContainer::HYBMunicipal_Other: {
          static std::vector<std::string> vctO = {
              "SNPRN", "GSPRN", "QHPRN", "NXPRN", "XJPRN", "IMPRN", "CQPRN",
              "GXPRN", "SCPRN", "GZPRN", "YNPRN", "XZPRN", "LNPRN", "JLPRN",
              "HLPRN", "SXPRN", "AHPRN", "JXPRN", "HAPRN", "HBPRN", "HNPRN"};
          if (!bi.IsMunicipal()) break;
          if (std::find(vctO.begin(), vctO.end(), pArea->Area_Code) ==
              vctO.end())
            return true;
        } break;
        case CBondContainer::HYBIndustrial: {
          if (bi.is_industry_bond() && !bi.IsBondFinancialInstitutions())
            return true;
        } break;
        case CBondContainer::HYBIndustrial_Estate: {
          if (bi.is_industry_bond() && !bi.IsBondFinancialInstitutions()) {
            if (strcmp(strSW_Realty,
                       pI->field((int)kIssuerInfo::SW_2021_Sector_Code)) == 0) {
              return true;
            }
          }
        } break;
        case CBondContainer::HYBIndustrial_Other: {
          if (bi.is_industry_bond() && !bi.IsBondFinancialInstitutions()) {
            if (strcmp(strSW_Realty,
                       pI->field((int)kIssuerInfo::SW_2021_Sector_Code)) != 0) {
              return true;
            }
          }
        } break;
        case CBondContainer::HYBOther: {
          if (bi.IsBondFinancialInstitutions()) {
            return true;
          }
        } break;
        default:
          break;
      }
    }
  }

  return false;
}

std::string CHighYieldBond::GetCombBondKey(int bondIndex) const {
  if (CBondContainer::instance().IsValidIndex(bondIndex)) {
    const CBondInfo& bi = CBondContainer::instance().ElementAtR(bondIndex);
    const char* bondKey = bi.GetBondKey();
    const char* market = bi.GetListedMarket();
    if (bondKey != nullptr && market != nullptr) {
      return std::string(bondKey) + std::string(".") + std::string(market);
    }
  }
  return "";
}